package org.esti.controller;

/**
 * @author Artem Loginov (logart)
 */

import org.esti.model.Book;
import org.esti.model.KnowledgeField;
import org.esti.model.User;
import org.esti.model.utils.KnowledgeFieldPropertyEditor;
import org.esti.service.BookService;
import org.esti.service.KnowledgeFieldService;
import org.esti.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

/**
 * This controller is used to perform different actions with books.
 * For example, upload book on the site, or view book for one of the knowledge fields.
 */
@Controller
public class BookController {

    private static final String BOOK_PATH_WITH_LOGIN = "/{login}/books";
    private static final String USER_MODEL_ATTRIBUTE_NAME = "user";
    private static final String BOOK_MODEL_ATTRIBUTE_NAME = "book";
    private static final String BOOK_VIEW_NAME = "book";
    private static final String BOOKS_VIEW_NAME = "books";
    private static final String BOOKS_MODEL_ATTRIBUTE_NAME = "books";


    @Autowired
    private BookService bookService;

    @Autowired
    private UserService userService;

    @Autowired
    private KnowledgeFieldService knowledgeFieldService;

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(org.esti.model.KnowledgeField.class,
                new KnowledgeFieldPropertyEditor(knowledgeFieldService));
    }

    /**
     * show form for adding book
     *
     * @param login of user to show him books
     * @param model set of parameters which will be passed to view.
     * @return view name
     */
    @RequestMapping(value = BOOK_PATH_WITH_LOGIN, params = "action=add_book", method = RequestMethod.GET)
    public String showAddBookForm(@PathVariable String login, Model model) {
        User user = userService.getUserByLogin(login);
        model.addAttribute(USER_MODEL_ATTRIBUTE_NAME, user);
        Book book = new Book();

        model.addAttribute(BOOK_MODEL_ATTRIBUTE_NAME, book);

        model.addAttribute("fieldsOfKnowledges", knowledgeFieldService.getKnowledgeFieldMap());

        return "add_book";
    }

    /**
     * process adding book
     *
     * @param login of user who will be the publisher of the book
     * @param book  which will be stored to DB
     * @param file  book file
     * @param model set of parameters which will be passed to view.
     * @return view name
     */
    @RequestMapping(value = BOOK_PATH_WITH_LOGIN, params = "action=add_book", method = RequestMethod.POST)
    public String addBook(
            @PathVariable String login,
            @ModelAttribute Book book,
            @RequestParam(value = "file", required = true) MultipartFile file,
            Model model) {

        User user = userService.getUserByLogin(login);
        book.setPublisher(user);

        model.addAttribute(USER_MODEL_ATTRIBUTE_NAME, userService.getUserByLogin(login));
        model.addAttribute(BOOK_MODEL_ATTRIBUTE_NAME, book);

        bookService.addBook(book, file);

        return "redirect:/" + login + "/books?action=add_book";

    }

    /**
     * show list of all needed book for specific user
     *
     * @param login of user who to show the books
     * @param model set of parameters which will be passed to view.
     * @return view name
     */
    @RequestMapping(value = BOOK_PATH_WITH_LOGIN, params = "action=manage_books")
    public String showUserBooks(@PathVariable String login, Model model) {
        model.addAttribute(USER_MODEL_ATTRIBUTE_NAME, userService.getUserByLogin(login));
        model.addAttribute(BOOKS_MODEL_ATTRIBUTE_NAME, bookService.getUserBooks(login));

        return BOOKS_VIEW_NAME;
    }

    /**
     * show list of all needed book by specific appraisal
     *
     * @param login of user who's appraisal is used to generate list of books
     * @param model set of parameters which will be passed to view.
     * @return view name
     */
    @RequestMapping(value = BOOK_PATH_WITH_LOGIN)
    public String showBooksByAppraisal(@PathVariable String login, Model model) {
        User user = userService.getUserByLogin(login);
        model.addAttribute(USER_MODEL_ATTRIBUTE_NAME, user);

        List<Book> books = bookService.getLevelBooks(user.getLevel().getId());

        model.addAttribute(BOOKS_MODEL_ATTRIBUTE_NAME, books);

        return BOOKS_VIEW_NAME;
    }

    /**
     * show list of all books stored in system
     *
     * @param model set of parameters which will be passed to view.
     * @return view name
     */
    @RequestMapping(value = "/books")
    public String showBooks(Model model) {
        model.addAttribute(BOOKS_MODEL_ATTRIBUTE_NAME, bookService.getBooks());
        return BOOKS_VIEW_NAME;
    }

    /**
     * process deleting book request
     *
     * @param id    of book which will be deleted
     * @param model set of parameters which will be passed to view.
     * @return view name
     */
    @RequestMapping(value = "/books/{id}", params = {"action=delete_book"})
    public String deleteBook(@PathVariable long id, Model model) {
        Book book = bookService.getBook(id);
        bookService.deleteBook(book);
        return "redirect:/books";
    }

    /**
     * show books list for specific knowledge field
     *
     * @param id    of knowledge field which used to generate list of books
     * @param model set of parameters which will be passed to view.
     * @return view name
     */
    @RequestMapping(value = "/knowledge-fields/{id}/books")
    public String showBooksByKnowledgeField(@PathVariable long id, Model model) {
        KnowledgeField knowledgeField = knowledgeFieldService.getKnowledgeFieldById(id);
        List<Book> books = bookService.getKnowledgeFieldBooks(knowledgeField);
        model.addAttribute(BOOKS_MODEL_ATTRIBUTE_NAME, books);
        return BOOKS_VIEW_NAME;
    }


}
